<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>环保数据监测平台 - 滚动加载</title>
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
      background-color: #f5f7fa;
      color: #333;
      line-height: 1.5;
    }

    .container {
      max-width: 1200px;
      margin: 0 auto;
      padding: 20px;
    }

    .header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 30px;
      padding-bottom: 20px;
      border-bottom: 1px solid #e6e6e6;
    }

    .header h1 {
      color: #409EFF;
      font-size: 24px;
      font-weight: 500;
    }

    .filter-bar {
      background-color: #fff;
      padding: 20px;
      border-radius: 4px;
      margin-bottom: 20px;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    }

    .data-container {
      min-height: 500px;
    }

    .data-list {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
      gap: 20px;
      margin-bottom: 20px;
    }

    .data-card {
      background-color: #fff;
      border-radius: 4px;
      overflow: hidden;
      transition: all 0.3s;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    }

    .data-card:hover {
      transform: translateY(-5px);
      box-shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.15);
    }

    .card-header {
      padding: 15px;
      background: linear-gradient(90deg, #409EFF, #64b5ff);
      color: white;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .card-body {
      padding: 15px;
    }

    .card-footer {
      padding: 10px 15px;
      border-top: 1px solid #eee;
      display: flex;
      justify-content: space-between;
      color: #909399;
      font-size: 12px;
    }

    .status-indicator {
      display: inline-block;
      width: 8px;
      height: 8px;
      border-radius: 50%;
      margin-right: 5px;
    }

    .status-excellent {
      background-color: #67C23A;
    }

    .status-good {
      background-color: #409EFF;
    }

    .status-fair {
      background-color: #E6A23C;
    }

    .status-poor {
      background-color: #F56C6C;
    }

    .loading-container,
    .end-container {
      text-align: center;
      padding: 20px;
      color: #909399;
    }

    .no-data {
      text-align: center;
      padding: 40px;
      color: #909399;
    }

    .value-display {
      font-size: 24px;
      font-weight: bold;
      margin: 10px 0;
      color: #409EFF;
    }

    .chart-container {
      height: 80px;
      margin: 10px 0;
    }

    .info-row {
      display: flex;
      justify-content: space-between;
      margin: 8px 0;
      font-size: 13px;
    }

    .info-label {
      color: #606266;
    }

    .info-value {
      color: #303133;
      font-weight: 500;
    }
  </style>
</head>

<body>
  <div id="app">
    <div class="container">
      <div class="header">
        <h1>环保数据监测平台</h1>
        <el-button type="primary" icon="el-icon-refresh" @click="resetData">重置数据</el-button>
      </div>

      <div class="filter-bar">
        <el-form :inline="true" :model="filters">
          <el-form-item label="监测区域">
            <el-select v-model="filters.region" placeholder="请选择区域" clearable>
              <el-option label="城东区" value="east"></el-option>
              <el-option label="城西区" value="west"></el-option>
              <el-option label="城南区" value="south"></el-option>
              <el-option label="城北区" value="north"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="空气质量">
            <el-select v-model="filters.quality" placeholder="请选择质量等级" clearable>
              <el-option label="优" value="excellent"></el-option>
              <el-option label="良" value="good"></el-option>
              <el-option label="中" value="fair"></el-option>
              <el-option label="差" value="poor"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="loadData">查询</el-button>
          </el-form-item>
        </el-form>
      </div>

      <div class="data-container">
        <div class="data-list">
          <div class="data-card" v-for="(item, index) in dataList" :key="index">
            <div class="card-header">
              <span>{{ item.name }}</span>
              <span class="status">
                <span class="status-indicator" :class="'status-' + item.quality"></span>
                {{ getQualityText(item.quality) }}
              </span>
            </div>
            <div class="card-body">
              <div class="value-display">
                AQI: {{ item.aqi }}
              </div>
              <div class="chart-container">
                <!-- 这里可以放置迷你图表 -->
                <el-progress :text-inside="true" :stroke-width="20" :percentage="item.percentage"
                  :color="getProgressColor(item.quality)">
                </el-progress>
              </div>
              <div class="info-row">
                <span class="info-label">PM2.5:</span>
                <span class="info-value">{{ item.pm25 }} μg/m³</span>
              </div>
              <div class="info-row">
                <span class="info-label">PM10:</span>
                <span class="info-value">{{ item.pm10 }} μg/m³</span>
              </div>
              <div class="info-row">
                <span class="info-label">SO₂:</span>
                <span class="info-value">{{ item.so2 }} μg/m³</span>
              </div>
              <div class="info-row">
                <span class="info-label">更新时间:</span>
                <span class="info-value">{{ item.time }}</span>
              </div>
            </div>
            <div class="card-footer">
              <span>{{ item.region }}</span>
              <span>更多信息</span>
            </div>
          </div>
        </div>

        <div v-if="loading" class="loading-container">
          <i class="el-icon-loading"></i> 加载中...
        </div>

        <div v-if="noMore" class="end-container">
          没有更多数据了
        </div>

        <div v-if="dataList.length === 0 && !loading" class="no-data">
          <i class="el-icon-warning-outline"></i>
          <p>暂无数据</p>

          <!-- <el-empty :image-size="200"></el-empty> -->
        </div>
      </div>

      <el-backtop title="回到顶部"></el-backtop>
    </div>
  </div>

  <script>
    new Vue({
      el: '#app',
      data() {
        return {
          filters: {
            region: '',
            quality: ''
          },
          dataList: [],
          loading: false,
          noMore: false,
          page: 1,
          pageSize: 10,
          scrollHandler: null,
        }
      },
      mounted() {
        this.loadData();
        // 注意防抖
        this.scrollHandler = this.debounce(() => {
          this.handleScroll();
        }, 200)
        window.addEventListener('scroll', this.scrollHandler);
      },
      beforeDestroy() {
        window.removeEventListener('scroll', this.scrollHandler);
      },
      methods: {
        // 防抖函数
        debounce(func, wait, immediate) {
          let timeout, args, context, timestamp, result

          const later = function () {
            // 据上一次触发时间间隔
            const last = +new Date() - timestamp

            // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
            if (last < wait && last > 0) {
              timeout = setTimeout(later, wait - last)
            } else {
              timeout = null
              // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
              if (!immediate) {
                result = func.apply(context, args)
                if (!timeout) context = args = null
              }
            }
          }

          return function (...args) {
            context = this
            timestamp = +new Date()
            const callNow = immediate && !timeout
            // 如果延时不存在，重新设定延时
            if (!timeout) timeout = setTimeout(later, wait)
            if (callNow) {
              result = func.apply(context, args)
              context = args = null
            }

            return result
          }
        },
        // 模拟API请求
        fetchData() {
          return new Promise(resolve => {
            setTimeout(() => {
              const newData = [];
              const regions = ['城东区', '城西区', '城南区', '城北区'];
              const qualities = ['excellent', 'good', 'fair', 'poor'];

              for (let i = 0; i < this.pageSize; i++) {
                const quality = qualities[Math.floor(Math.random() * qualities.length)];
                newData.push({
                  name: `监测点 ${(this.page - 1) * this.pageSize + i + 1}`,
                  aqi: Math.floor(Math.random() * 100) + 30,
                  pm25: (Math.random() * 100).toFixed(1),
                  pm10: (Math.random() * 150).toFixed(1),
                  so2: (Math.random() * 50).toFixed(1),
                  quality: quality,
                  percentage: Math.floor(Math.random() * 100),
                  region: regions[Math.floor(Math.random() * regions.length)],
                  time: new Date().toLocaleTimeString()
                });
              }
              resolve(newData);
            }, 800); // 模拟网络延迟
          });
        },

        // 加载数据
        async loadData() {
          if (this.loading || this.noMore) return;

          this.loading = true;
          try {
            const newData = await this.fetchData();

            if (this.page === 1) {
              this.dataList = [];
            }

            if (newData.length > 0) {
              this.dataList = [...this.dataList, ...newData];
              this.page++;
            }

            // 模拟数据有限的情况
            if (this.page > 5) {
              this.noMore = true;
            }
          } catch (error) {
            console.error('加载数据失败:', error);
          } finally {
            this.loading = false;
          }
        },

        // 处理滚动事件
        handleScroll() {
          const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
          const windowHeight = window.innerHeight;
          const scrollHeight = document.documentElement.scrollHeight;

          // 滚动到距离底部200px时加载更多
          if (scrollTop + windowHeight >= scrollHeight - 200 && !this.loading && !this.noMore) {
            this.loadData();
          }
        },

        // 获取质量等级文本
        getQualityText(quality) {
          const map = {
            'excellent': '优',
            'good': '良',
            'fair': '中',
            'poor': '差'
          };
          return map[quality] || '未知';
        },

        // 获取进度条颜色
        getProgressColor(quality) {
          const map = {
            'excellent': '#67C23A',
            'good': '#409EFF',
            'fair': '#E6A23C',
            'poor': '#F56C6C'
          };
          return map[quality] || '#409EFF';
        },

        // 重置数据
        resetData() {
          this.page = 1;
          this.noMore = false;
          this.dataList = [];
          this.loadData();
        }
      }
    });
  </script>
</body>

</html>